﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace UtilZ.Dotnet.Ex.TTLV
{
    //Encoding
    public partial class TTLVHelper
    {
        #region Encoding
        /// <summary>
        /// 转换为bytes
        /// </summary>
        /// <param name="obj">目标对象</param>
        /// <returns>转换结果bytes</returns>
        public static byte[] Encoding(object obj)
        {
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }

            Type type = obj.GetType();
            var ttlvTypeStructTree = GetTypeStructTree(type);

            using (var ms = new MemoryStream())
            {
                var bw = new BinaryWriter(ms);
                PrimitiveEncoding(bw, ttlvTypeStructTree.ChildDic, obj);
                bw.Flush();
                return ms.GetBuffer().Take((int)ms.Length).ToArray();
            }
        }

        private static void PrimitiveEncoding(BinaryWriter bw, Dictionary<int, TTLVStructNode> childDic, object obj)
        {
            foreach (var node in childDic.Values)
            {
                var value = node.GetValue(obj);
                if (value == null)
                {
                    //如果字段值为null，则忽略该字段
                    continue;
                }

                switch (node.TTLVType)
                {
                    case TTLVType.BasicType:
                        EncodingBasicType(bw, node, value);
                        break;
                    case TTLVType.Convert:
                        EncodingConvert(bw, node, value);
                        break;
                    case TTLVType.Object:
                        EncodingObject(bw, node, value);
                        break;
                    case TTLVType.Array:
                    case TTLVType.IList:
                        EncodingCollection(bw, node, value);
                        break;
                    default:
                        throw new NotImplementedException(string.Format("未知类型", node.TTLVType.ToString()));
                }
            }
        }

        private static void EncodingCollection(BinaryWriter bw, TTLVStructNode node, object collectionObj)
        {
            List<byte> buffer2 = new List<byte>();
            var collection = (IEnumerable)collectionObj;
            foreach (var item in collection)
            {
                EncodingObject(bw, node, item);
            }

            AddTTLVNodeValue(bw, node, buffer2.ToArray());
        }

        private static void EncodingObject(BinaryWriter bw, TTLVStructNode node, object objValue)
        {
            List<byte> buffer2 = new List<byte>();
            Dictionary<int, TTLVStructNode> childDic = GetTTLVStructNodeChilds(node);
            PrimitiveEncoding(bw, childDic, objValue);
            AddTTLVNodeValue(bw, node, buffer2.ToArray());
        }

        private static void EncodingConvert(BinaryWriter bw, TTLVStructNode node, object objValue)
        {
            var valueBuffer = node.Converter.ConvertToBytes(node.Tag, objValue, node.ElementType, node.ConverterPara);
            AddTTLVNodeValue(bw, node, valueBuffer);
        }

        private static void EncodingBasicType(BinaryWriter bw, TTLVStructNode node, object objValue)
        {
            byte[] valueBuffer = TTLVCommon.ConvertToBytes(node.TypeCode, objValue);
            AddTTLVNodeValue(bw, node, valueBuffer);
        }

        private static void AddTTLVNodeValue(BinaryWriter bw, TTLVStructNode node, byte[] valueBuffer)
        {
            _codec.WriteNode(bw, node.Tag, node.TypeCode, valueBuffer);
        }
        #endregion
    }
}
